import os
import sys
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageGrab
import requests
from io import BytesIO
import threading
import win32clipboard
import pythoncom
import time
import base64
import urllib.parse

# 自动安装缺失库
def install_package(package):
    try:
        __import__(package)
    except ImportError:
        import subprocess
        subprocess.check_call([sys.executable, "-m", "pip", "install", package])

# 尝试导入所需库
try:
    from tkinterdnd2 import TkinterDnD, DND_FILES
except ImportError:
    install_package('tkinterdnd2')
    try:
        from tkinterdnd2 import TkinterDnD, DND_FILES
    except ImportError:
        messagebox.showerror("错误", "请手动安装 tkinterdnd2: pip install tkinterdnd2")
        sys.exit()

# 百度云OCR API配置 - 请替换为您自己的API密钥
API_KEY = "UtTsgoQfBPQ8lLNCEZmAhEAB"
SECRET_KEY = "zQkztFw78hXaczf6gMrEQhRI4PBocnAB"
class BaiduPlateRecognizer:
    """百度车牌识别专用类"""
    def __init__(self):
        self.access_token = self.get_access_token()
        self.url = f"https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate?access_token={self.access_token}"
        self.headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        }

    def get_access_token(self):
        """获取百度API访问令牌"""
        url = "https://aip.baidubce.com/oauth/2.0/token"
        params = {
            "grant_type": "client_credentials",
            "client_id": API_KEY,
            "client_secret": SECRET_KEY
        }
        try:
            response = requests.post(url, params=params, timeout=5)
            return response.json().get("access_token")
        except Exception as e:
            raise Exception(f"获取access_token失败: {str(e)}")

class ClipboardMonitor:
    """剪贴板监控器，用于捕获微信图片"""
    def __init__(self, callback):
        self.callback = callback
        self.last_data = None
        self.running = True
        self.thread = threading.Thread(target=self.monitor)
        self.thread.daemon = True
        self.thread.start()

    def monitor(self):
        while self.running:
            try:
                win32clipboard.OpenClipboard()
                if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_BITMAP):
                    data = "bitmap"
                    if data != self.last_data:
                        self.callback()
                        self.last_data = data
                win32clipboard.CloseClipboard()
            except:
                pass
            time.sleep(1)

    def stop(self):
        self.running = False

class VehicleScrapApp(TkinterDnD.Tk):
    def __init__(self):
        super().__init__()
        self.title("车辆报废厂照片管理")
        self.geometry("900x700")
        
        # 窗口居中显示
        self.center_window()
        
        # 初始化变量
        self.image_paths = []
        self.processed_results = []
        self.output_dir = "车辆报废厂照片管理"
        self.first_plate_number = None  # 新增这行初始化代码
        os.makedirs(self.output_dir, exist_ok=True)
        
        # 创建界面
        self.create_widgets()
        
        # 启动剪贴板监控
        self.clipboard_monitor = ClipboardMonitor(self.handle_wechat_image)
        
        # 绑定窗口关闭事件
        self.protocol("WM_DELETE_WINDOW", self.on_close)
        
    def center_window(self):
        """使窗口在屏幕上居中显示"""
        self.update_idletasks()  # 更新窗口信息
        width = self.winfo_width()  # 获取窗口宽度
        height = self.winfo_height()  # 获取窗口高度
        x = (self.winfo_screenwidth() // 2) - (width // 2)  # 计算x坐标
        y = (self.winfo_screenheight() // 2) - (height // 2)  # 计算y坐标
        self.geometry(f"{width}x{height}+{x}+{y}")  # 设置窗口位置

    def create_widgets(self):
        # 顶部标题
        title_frame = ttk.Frame(self)
        title_frame.pack(fill="x", padx=10, pady=10)
        
        ttk.Label(title_frame, text="", font=("微软雅黑", 1)).pack(side="left")
        
        # 操作按钮
        btn_frame = ttk.Frame(self)
        btn_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Button(btn_frame, text="选择文件", command=self.select_files).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="清空列表", command=self.clear_list).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="处理图片", command=self.process_images).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="打开输出目录", command=self.open_output_dir).pack(side="right", padx=5)
        
        # 拖放区域
        self.drop_frame = tk.LabelFrame(self, text="拖放区", relief="sunken", borderwidth=2)
        self.drop_frame.pack(fill="both", expand=True, padx=10, pady=5)
        
        self.drop_label = ttk.Label(self.drop_frame, text="拖放图片到这里（支持从微信复制图片）", 
                                  anchor="center", foreground="gray")
        self.drop_label.pack(fill="both", expand=True, padx=10, pady=40)
        
        # 注册拖放事件
        self.drop_frame.drop_target_register(DND_FILES)
        self.drop_frame.dnd_bind('<<Drop>>', self.on_drop)
        
        # 文件列表
        self.listbox = tk.Listbox(self, height=8)
        self.listbox.pack(fill="x", padx=10, pady=5)
        
        # 进度条
        self.progress = ttk.Progressbar(self, orient="horizontal", mode="determinate")
        self.progress.pack(fill="x", padx=10, pady=5)
        
        # 日志区域
        self.log_text = tk.Text(self, height=10, state="disabled")
        self.log_text.pack(fill="both", expand=True, padx=10, pady=5)
        
        scrollbar = ttk.Scrollbar(self.log_text)
        scrollbar.pack(side="right", fill="y")
        self.log_text.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.log_text.yview)
        # 添加底部版权信息
        self.copyright_frame = tk.Frame(self, bg="yellow")
        self.copyright_frame.pack(fill="x", side="bottom", pady=5)
        
        copyright_text = "关注速光网络软件开发，抖音号：dubaishun12 私信博主，免费获取注册码"
        self.copyright_label = tk.Label(
            self.copyright_frame, 
            text=copyright_text,
            bg="yellow",
            font=("微软雅黑", 10)
        )
        self.copyright_label.pack(expand=True)

    def on_drop(self, event):
        """处理拖放文件"""
        files = self.tk.splitlist(event.data)
        valid_files = [f for f in files if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp'))]
        
        if not valid_files:
            self.log_message("错误: 只支持图片文件(.png, .jpg, .jpeg, .bmp)")
            return
        
        self.add_files(valid_files)

    def select_files(self):
        """文件选择对话框"""
        files = filedialog.askopenfilenames(
            title="选择车辆图片",
            filetypes=[("图片文件", "*.png *.jpg *.jpeg *.bmp")]
        )
        if files:
            self.add_files(files)

    def add_files(self, files):
        """添加文件到处理列表"""
        new_files = [f for f in files if f not in self.image_paths]
        self.image_paths.extend(new_files)
        
        # 更新列表显示
        self.listbox.delete(0, tk.END)
        for file in self.image_paths:
            self.listbox.insert(tk.END, os.path.basename(file))
        
        self.drop_label.config(text=f"已添加 {len(self.image_paths)} 张图片")
        self.log_message(f"添加 {len(new_files)} 张图片")

    def handle_wechat_image(self):
        """处理微信图片（通过剪贴板）"""
        try:
            img = ImageGrab.grabclipboard()
            if img:
                temp_dir = os.path.join(self.output_dir, "temp")
                os.makedirs(temp_dir, exist_ok=True)
                temp_path = os.path.join(temp_dir, f"wechat_{int(time.time())}.png")
                img.save(temp_path)
                self.add_files([temp_path])
                self.log_message("已从剪贴板导入微信图片")
        except Exception as e:
            self.log_message(f"微信图片处理失败: {str(e)}")

    def process_images(self):
        """处理图片"""
        if not self.image_paths:
            self.log_message("错误: 没有可处理的图片")
            return
        
        # 禁用按钮防止重复处理
        for child in self.winfo_children():
            if isinstance(child, ttk.Button):
                child.config(state="disabled")
        
        # 重置进度条
        self.progress["value"] = 0
        self.progress["maximum"] = len(self.image_paths)
        
        # 在新线程中处理
        threading.Thread(target=self._process_images_thread, daemon=True).start()

    def _process_images_thread(self):
        """图片处理线程"""
        try:
            recognizer = BaiduPlateRecognizer()
            
            for i, image_path in enumerate(self.image_paths, 1):
                try:
                    # 更新进度
                    self.after(0, self.progress.step)
                    self.after(0, self.log_message, f"正在处理 {i}/{len(self.image_paths)}: {os.path.basename(image_path)}")
                    
                    # 读取图片
                    with open(image_path, 'rb') as f:
                        image_data = f.read()
                    
                    # 识别车牌号
                    plate_number = self.detect_plate_number(recognizer, image_data)
                    
                    # 记录第一个检测到的车牌号
                    if plate_number and not self.first_plate_number:
                        self.first_plate_number = plate_number
                        self.after(0, self.log_message, f"第一个识别到的车牌号: {plate_number}")
                    
                    # 处理未识别的情况
                    if not plate_number:
                        if self.first_plate_number:  # 如果已经有识别出的车牌号
                            plate_number = self.first_plate_number
                            self.after(0, self.log_message, f"未识别到车牌号，将放入第一个检测到的车牌号目录: {plate_number}")
                        else:
                            self.after(0, self.log_message, "警告: 无法识别图片中的车牌号且没有其他已识别的车牌号")
                            continue
                    
                    # 保存图片
                    saved_path = self.save_image(image_data, plate_number, os.path.basename(image_path))
                    
                    # 记录结果
                    self.processed_results.append({
                        "original": image_path,
                        "plate": plate_number,
                        "saved": saved_path
                    })
                    
                except Exception as e:
                    self.after(0, self.log_message, f"处理失败: {str(e)}")
            
            self.after(0, self.log_message, f"处理完成! 共处理 {len(self.processed_results)} 张图片")
            
        except Exception as e:
            self.after(0, self.log_message, f"处理出错: {str(e)}")
        finally:
            self.after(0, self.enable_buttons)
            self.first_plate_number = None  # 处理完成后重置

    def detect_plate_number(self, recognizer, image_data):
        """使用百度专用车牌识别接口"""
        try:
            # 将图片转为base64编码
            image_base64 = base64.b64encode(image_data).decode('utf8')
            image_urlencoded = urllib.parse.quote_plus(image_base64)
            
            payload = f'image={image_urlencoded}&multi_detect=false'
            
            response = requests.post(
                recognizer.url,
                headers=recognizer.headers,
                data=payload,
                timeout=10
            )
            
            result = response.json()
            
            # 解析车牌识别结果
            if 'words_result' in result:
                plate_number = result['words_result']['number']
                # 车牌号有效性验证
                if plate_number and len(plate_number) >= 6:
                    # 去除可能存在的空格和特殊字符
                    plate_number = ''.join(c for c in plate_number if c.isalnum())
                    return plate_number.upper()  # 统一转为大写
            elif 'error_msg' in result:
                raise Exception(result['error_msg'])
            return None
            
        except Exception as e:
            #self.log_message(f"车牌识别: {str(e)}")
            return None

    def save_image(self, image_data, plate_number, filename):
        """保存图片到对应车牌目录"""
        try:
            # 创建车牌目录
            plate_dir = os.path.join(self.output_dir, plate_number)
            os.makedirs(plate_dir, exist_ok=True)
            
            # 处理文件名冲突
            base, ext = os.path.splitext(filename)
            counter = 1
            while os.path.exists(os.path.join(plate_dir, filename)):
                filename = f"{base}_{counter}{ext}"
                counter += 1
            
            # 保存图片
            output_path = os.path.join(plate_dir, filename)
            with open(output_path, 'wb') as f:
                f.write(image_data)
            
            return output_path
        except Exception as e:
            raise Exception(f"保存图片失败: {str(e)}")

    def clear_list(self):
        """清空文件列表"""
        self.image_paths = []
        self.listbox.delete(0, tk.END)
        self.drop_label.config(text="拖放图片到这里（支持从微信复制图片）")
        self.log_message("已清空文件列表")

    def open_output_dir(self):
        """打开输出目录"""
        if os.path.exists(self.output_dir):
            os.startfile(self.output_dir)
        else:
            self.log_message("输出目录不存在")

    def enable_buttons(self):
        """启用所有按钮"""
        for child in self.winfo_children():
            if isinstance(child, ttk.Button):
                child.config(state="normal")

    def log_message(self, message):
        """记录日志"""
        self.log_text.config(state="normal")
        self.log_text.insert("end", message + "\n")
        self.log_text.see("end")
        self.log_text.config(state="disabled")
        self.update_idletasks()

    def on_close(self):
        """关闭窗口时的清理工作"""
        self.clipboard_monitor.stop()
        self.destroy()

if __name__ == "__main__":
    try:
        # Windows下设置DPI感知
        if os.name == 'nt':
            from ctypes import windll
            windll.shcore.SetProcessDpiAwareness(1)
        
        app = VehicleScrapApp()
        app.mainloop()
    except Exception as e:
        messagebox.showerror("错误", f"程序启动失败: {str(e)}")